//
//  QFXmppManager.m
//  ChatDemo
//
//  Created by yang on 17/11/13.
//  Copyright (c) 2013 北京千锋互联科技有限公司. All rights reserved.
//

#import "QFXmppManager.h"
#import "MessageModel.h"

@implementation QFXmppManager

- (id)init
{
    self = [super init];
    if (self) {
        _currUser = [[UserModel alloc] init];
        _allFriendList = [[NSMutableArray alloc] init];
        _xmppStream = [[XMPPStream alloc] init];
        // 在这里并没有连接....
        // xxx.delegate = self;
        
        xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
        
        xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
        
        xmppRoster.autoFetchRoster = YES;
        xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
        [xmppRoster activate:_xmppStream];
        //设置连接的服务器地址
        [_xmppStream setHostName:@"1000phone.net"];
        //设置要连接的服务器的端口号
        [_xmppStream setHostPort:5222];
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
       [xmppRosterStorage mainThreadManagedObjectContext];
    }
    return self;
}
+ (id) shareInstance {
    static id _s;
    if (_s == nil) {
        _s = [[[self class] alloc] init];
    }
    return _s;
}
- (void) registerUser:(NSString *)jid
         withPassword:(NSString *)pass
       withCompletion:( void (^) (BOOL ret, NSError *err))cb {
    saveRegCb = [cb copy];
    isInRegisting = YES;
    // 真正的注册...
    if ([_xmppStream isConnected]) {
        [_xmppStream disconnect];
    }
    // sip
    _currUser.jid = jid;
    _currUser.password = pass;
    
    // 把jid字符串转化成XMPPJID对象(xmpp中用于标记用户账号的类)
    // nsstring--->nsurl
    XMPPJID *myjid = [XMPPJID jidWithString:jid];
    // 给这个xmpp流设置一个账号
    [_xmppStream setMyJID:myjid];
    NSError *err = nil;
    // 这个函数决不能调用2次
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&err];
    // 异步注册 需要代理
    if (ret == NO) {
        if (saveRegCb) {
            saveRegCb(NO, err);
        }
    }
}


//连接openfire服务器后，调用此方法
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
    NSLog(@"连接上了  %@", NSStringFromSelector(_cmd));
    // 输入密码
    // 给xmppserver/openfire pass
    // state machine状态机
    NSError *err = nil;
    if (isInRegisting) {
        // 一旦注册就回到xmppStreamDidRegister
        [_xmppStream registerWithPassword:_currUser.password error:&err];
    } else {
        // 如果对于已经有的用户 这是授权密码
        [_xmppStream authenticateWithPassword:_currUser.password error:&err];
        // 一旦授权完成。。。就会进入密码授权正确
    }
    // 成功失败
}

//注册成功后，调用此方法
- (void)xmppStreamDidRegister:(XMPPStream *)sender {
    //    NSLog(@"function  %@", NSStringFromSelector(_cmd));
    if (saveRegCb) {
        saveRegCb(YES, nil);
    }
}
/**
 * This method is called if registration fails.
 **/
//注册失败后，调用此方法
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error {
    //    NSLog(@"function  %@", NSStringFromSelector(_cmd));
    //    NSLog(@"error is %@", [error description]);
    if (saveRegCb) {
        NSError *myerr = [NSError errorWithDomain:error.description code:-1 userInfo:nil];
        saveRegCb(NO, myerr);
    }
}
/*
 <iq xmlns="jabber:client" type="error"
 to="1000phone.net/fbfd0ebd">
 <query xmlns="jabber:iq:register">
 <username>test1117</username>
 <password>123456</password>
 </query>
 <error code="409" type="cancel">
 <conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
 </error>
 </iq>
 */
#pragma mark - 登陆部分
- (void) loginUser:(NSString *)jid
      withPassword:(NSString *)pass
    withCompletion:( void (^) (BOOL ret, NSError *err))cb {
    saveLoginCb = [cb copy];
    isInRegisting = NO;
    // 登陆分为2步
    // 1. 给服务器输入账, 2. 给服务器输入密码
    _currUser.jid = jid;
    _currUser.password = pass;
    XMPPJID *myjid = [XMPPJID jidWithString:jid];
    if ([_xmppStream isConnected]) {
        [_xmppStream disconnect];
    }
    [_xmppStream setMyJID:myjid];
    NSError *error = nil;
    // 1. 给server
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];
    if (ret == NO) {
        saveLoginCb(NO, error);
    }
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
    // 授权成功
    //    NSLog(@"function is %@", NSStringFromSelector(_cmd));
    // 可以上线...goonline
    if (saveLoginCb) {
        saveLoginCb(YES, nil);
    }
    // 上线//获取所有好友
    [self goOnline];
    // 取得所有好友信息
    // 取得当前上线是谁
    [self getAllFriends];
}

// IQ Information Query 信息查询
//向openfire服务器获取用户列表
-(void)getAllFriends{
    // KissXML / GDATA
    NSXMLElement *query = [NSXMLElement
                           elementWithName:@"query" xmlns:@"jabber:iq:roster"];
    // 用来产生一个节点 <query xmlns="jabber:iq:roster"/>
    // <query xmlns="jabber:iq:roster"></query>
    NSXMLElement *iq = [NSXMLElement
                        elementWithName:@"iq"];
    // <iq></iq> = <iq/>
    [iq addAttributeWithName:@"type" stringValue:@"get"];
    // <iq type="get"></iq> = <iq/>
    [iq addChild:query];
    //<iq type="get"><query xmlns="jabber:iq:roster"></query></iq>
    
    // NSXMLElement就是一个节点...
    /*
     <iq type="get">
     <query xmlns="jabber:iq:roster"/>
     </iq>
     */
    NSLog(@"all friends %@", iq);
    // 传给服务器... 服务器要返回 XML
    [_xmppStream sendElement:iq];
}
/**
 * This method is called if authentication fails.
 **/
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error {
    //    NSLog(@"function is %@", NSStringFromSelector(_cmd));
    if (saveLoginCb) {
        saveLoginCb(NO, [NSError errorWithDomain:error.description code:-1 userInfo:nil]);
    }
}

- (void) goOnline {
    // Presence
    //    XMPPPresence *p = [XMPPPresence presence];
    XMPPPresence *p = [XMPPPresence presenceWithType:@"away"];
    //    p.status = @"be right back";
    NSLog(@"p is %@", p);
    // <presence/>
    //<presence type="away"/>
    
    [_xmppStream sendElement:p];
    
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
    // 取得第一个节点
    NSLog(@"iq is %@", iq);
    NSXMLElement *query = iq.childElement;
    for (NSXMLElement *oneChild in query.children) {
        NSString *jid = [oneChild attributeStringValueForName:@"jid"];
        NSLog(@"jid is %@", jid);
        //        UserModel *um = [[UserModel alloc] init];
        //        um.jid = jid;
        //        um.status = @"unavailable";
        //        [_allFriendList addObject:um];
        [self addOrUpdateUser:jid withStatus:@"unavailable" needToChangeStatus:NO];
    }
    //    NSLog(@"func %@ IQ %@", NSStringFromSelector(_cmd), iq);
    /*
     <iq xmlns="jabber:client" type="result" to="changcunyuan@1000phone.net/9311ab0d">
     <query xmlns="jabber:iq:roster">
     <item jid="test22@1000phone.net" name="" subscription="both"><group>?????</group></item>
     <item jid="qianfeng@1000phone.net" name="qianfeng" subscription="both"><group>?????</group></item>
     <item jid="wjw@1000phone.net" name="wang" subscription="both"><group>?????</group></item>
     </query>
     </iq>
     */
    return YES;
}
//获取消息后
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
    NSLog(@"func %@ message %@", NSStringFromSelector(_cmd), message);
    if ([message isChatMessage]) {
        if ([message isChatMessageWithBody]) {
            NSString *body = [message body];
            NSString *from = [[message from] bare];
            NSString *to = [[message to] bare];
            MessageModel *mm = [[MessageModel alloc] init];
            mm.msg = body;
            mm.from = from;
            mm.to  = to;
            if (saveMessageCb) {
                saveMessageCb(mm);
            } else {
                // 存在离线数组中...
            }
        }
    }
    /*
     <message xmlns="jabber:client" type="chat" id="purpledaef35f2" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2"><active xmlns="http://jabber.org/protocol/chatstates"/><body>hi</body></message>
     */
}
//上线
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
    // 是数组中某个人的信息 状态改变...
    NSString *jid = [presence attributeStringValueForName:@"from"];
    NSString *status = @"online";
    // 判断里面show
    for (NSXMLElement *oneChild in presence.children) {
        if ([oneChild.name isEqualToString:@"show"]) {
            status = @"away";
        }
    };
    // qianfeng@1000phone.net/YangMac-2
    XMPPJID *hisJid = [XMPPJID jidWithString:jid];
    jid = [NSString stringWithFormat:@"%@@%@", hisJid.user, hisJid.domain];
    NSLog(@"online jid %@", jid);
    [self addOrUpdateUser:jid withStatus:status];
    
    //    NSLog(@"func %@ presence %@", NSStringFromSelector(_cmd), presence);
    /*
     <presence xmlns="jabber:client"
     from="qianfeng@1000phone.net/YangMac-2" to="changcunyuan@1000phone.net/41efe16c">
     <c xmlns="http://jabber.org/protocol/caps" node="http://pidgin.im/" hash="sha-1" ver="DdnydQG7RGhP9E3k9Sf+b+bF0zo="/>
     <x xmlns="vcard-temp:x:update">
     <photo>6d9e2a9ac708ea7f2b43876d8c698a70ae7e59dc</photo>
     </x>
     </presence>
     
     Away
     <presence xmlns="jabber:client" from="qianfeng@1000phone.net/YangMac-2" to="changcunyuan@1000phone.net">
     <show>away</show>
     <status>Away</status>
     <c xmlns="http://jabber.org/protocol/caps" node="http://pidgin.im/" hash="sha-1" ver="DdnydQG7RGhP9E3k9Sf+b+bF0zo="/>
     <x xmlns="vcard-temp:x:update">
     <photo>6d9e2a9ac708ea7f2b43876d8c698a70ae7e59dc</photo>
     </x>
     </presence>
     Invisble
     
     <presence xmlns="jabber:client" from="qianfeng@1000phone.net/YangMac-2" to="changcunyuan@1000phone.net">
     <show>away</show>
     <c xmlns="http://jabber.org/protocol/caps" node="http://pidgin.im/" hash="sha-1" ver="DdnydQG7RGhP9E3k9Sf+b+bF0zo="/>
     <x xmlns="vcard-temp:x:update">
     <photo>6d9e2a9ac708ea7f2b43876d8c698a70ae7e59dc</photo>
     </x>
     </presence>
     */
}

/*
 
 <message xmlns="jabber:client" type="chat" id="purplea4d0f3b0" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2">
 <composing xmlns="http://jabber.org/protocol/chatstates"/>
 </message>
 
 <message xmlns="jabber:client" type="chat" id="purplea4d0f3b1" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2">
 <active xmlns="http://jabber.org/protocol/chatstates"/>
 </message>
 <message xmlns="jabber:client" type="chat" id="purplea4d0f3b2" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2">
 <composing xmlns="http://jabber.org/protocol/chatstates"/>
 </message>
 <message xmlns="jabber:client" type="chat" id="purplea4d0f3b4" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2">
 <active xmlns="http://jabber.org/protocol/chatstates"/>
 <body>hi</body>
 </message>
 
 <message xmlns="jabber:client" type="chat" id="purplea4d0f3b5" to="changcunyuan@1000phone.net" from="qianfeng@1000phone.net/YangMac-2">
 <active xmlns="http://jabber.org/protocol/chatstates"/>
 </message>
 
 */

// 增加这个人，如果这个人已经存在了 就不要改变状态
- (void)addOrUpdateUser:(NSString *)jid withStatus:(NSString *)status needToChangeStatus:(BOOL)yesOrNO{
    for (UserModel *um in _allFriendList) {
        if ([um.jid isEqualToString:jid]) {
            return;
        }
    }
    [self addOrUpdateUser:jid withStatus:status];
}

- (void) addOrUpdateUser:(NSString *)jid withStatus:(NSString *)status {
    for (UserModel *um in _allFriendList) {
        if ([um.jid isEqualToString:jid]) {
            // 存在这个
            um.status = status;
            return;
        }
    }
    UserModel *um = [[UserModel alloc] init];
    um.jid = jid;
    um.status = status;
    [_allFriendList addObject:um];
    if (saveFriendsCb) {
        saveFriendsCb(_allFriendList);
    }
}

- (void) getAllFriends:( void (^) (NSArray *) ) cb {
    saveFriendsCb = [cb copy];
    if (saveFriendsCb) {
        saveFriendsCb(_allFriendList);
    }
}

- (void) registerForMessage:( void (^) (MessageModel *mm) )cb {
    saveMessageCb = [cb copy];
}

//发送消息
- (void) sendMessage:(NSString *)msg withType:(MessageType)type toUser:(UserModel *)toUser withCompletion:(void (^)(BOOL ret))cb {
    saveSendMessageFinishCb = [cb copy];
    if (1 /*type == kMsgText*/) {
        /*
         <message xmlns="jabber:client" type="chat"
         id="purpledaef3600"
         to="changcunyuan@1000phone.net"
         from="qianfeng@1000phone.net/YangMac-2">
         <active xmlns="http://jabber.org/protocol/chatstates"/>
         <body>hi</body>
         </message>
         */
        XMPPJID *toJid = [XMPPJID jidWithString:toUser.jid];//要发送的账号
        XMPPMessage *oneMessage = [[XMPPMessage alloc] initWithType:@"chat" to:toJid];
        if (type ==kMsgImage) {
            [oneMessage addAttributeWithName:@"msg_type" stringValue:@"pic"];
        } else if (type == kMsgVoice) {
            [oneMessage addAttributeWithName:@"msg_type" stringValue:@"voice"];
        }
        [oneMessage addBody:msg];
        //NSLog(@"oneMessage %@", oneMessage);
        // 发到服务器上
        [_xmppStream sendElement:oneMessage];
    }
}

- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
    if (saveSendMessageFinishCb) {
        saveSendMessageFinishCb(YES);
    }
}

- (void)addFriendWithName:(NSString *)userName andMessage:(NSString *)message{
    if (message.length) {
        XMPPMessage *mes=[XMPPMessage messageWithType:@"chat" to:[XMPPJID jidWithUser:userName domain:@"1000phone.net" resource:@"IOS"]];
        [mes addChild:[DDXMLNode elementWithName:@"body" stringValue:message]];
        [_xmppStream sendElement:mes];
    }
    [xmppRoster subscribePresenceToUser:[XMPPJID jidWithUser:userName domain:@"1000phone.net" resource:@"IOS"]];
}

@end
